using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Runtime.Caching;
using HCD.Const;
using HCD.Entities;
using HCD.User.Dtos;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Partner.Utility;
using System.Linq;
using System.Threading.Tasks;

namespace HCD.User
{
    [Route("api/[controller]/[action]"), ApiController]
    public class UserAppService : AsyncCrudAppService<UserEntity,UserDto,long, UserGetAllInput, UserAddInput, UserEditInput, EntityDto<long>, EntityDto<long>>, IUserAppService
    {
        private readonly IRepository<UserEntity, long> _userRep ;
        public IRepository<StaffDictV,string> StaffDictVRep{get;set;}
        public ICacheManager CacheManager { get; set; }
        public UserAppService(IRepository<UserEntity,long> repository)
        : base(repository)
        {
            _userRep = repository;
            LocalizationSourceName = EnterpriseConsts.LocalizationSourceName;
        }
        [HttpPost,ActionName("Add"), NonAction]
        public override async Task<UserDto> CreateAsync(UserAddInput input)
        {
            return await base.CreateAsync(input);
        }

        [HttpPut, ActionName("Edit"), NonAction]
        public override async Task<UserDto> UpdateAsync(UserEditInput input)
        {
            return await base.UpdateAsync(input);
        }

        [HttpDelete, ActionName("Delete"), NonAction]
        public override async Task DeleteAsync(EntityDto<long> input)
        {
            await base.DeleteAsync(input);
        }

        [HttpGet, ActionName("Get"), NonAction]
        public override async Task<UserDto> GetAsync([FromQuery]EntityDto<long> input)
        {
            var re = await base.GetAsync(input);
            var staff = await StaffDictVRep.FirstOrDefaultAsync(m => m.UserName == re.UserName);
            return ObjectMapper.Map(staff,re);
        }

        [HttpGet, ActionName("GetList"),UnitOfWork(isTransactional:false)]
        public override async Task<PagedResultDto<UserDto>> GetAllAsync([FromQuery]UserGetAllInput input)
        {
            var users = await base.GetAllAsync(input);
            if(users.Items?.Count>0)
            {
                var ids = users.Items.Select(m=>m.UserName);
                var vUsers =  await StaffDictVRep.GetAllListAsync(m=>ids.Contains(m.UserName)); 
                users.Items = ObjectMapper.Map(vUsers,users.Items);
            }
            return users;
        }
        protected override IQueryable<UserEntity> CreateFilteredQuery(UserGetAllInput input)
        {
            return base.CreateFilteredQuery(input);
        }

        [NonAction,UnitOfWork(isTransactional:false)]
        public async Task<UserMiniDto> Login(LoginInput loginDto)
        {
            var staff = await StaffDictVRep.GetAll().AsNoTracking().FirstOrDefaultAsync(m => m.UserName == loginDto.UserName);
            if (staff == null)
                throw new BizException(L("UserIsNotFound"));
            var user = await _userRep.GetAll().AsNoTracking().FirstOrDefaultAsync(m => m.UserName == loginDto.UserName);
            UserMiniDto re = null;
            if (user == null)
            {
                var userEntity = new UserEntity{ UserName = staff.UserName,InitialPwd=true,PasswordHash=loginDto.Password};
                userEntity.Id =await _userRep.InsertAndGetIdAsync(userEntity);
                re = ObjectMapper.Map<UserMiniDto>(userEntity);
            }
            else
            {
                if (user.PasswordHash != loginDto.Password)
                {
                    //该账号1小时内的登录错误次数
                    var errCount = await CacheManager.GetCache<string,int>(Const.RedisConst.AccessFailed).GetAsync(loginDto.UserName, key => Task.FromResult(0));
                    //记录错误登录次数
                    await CacheManager.GetCache<string,int>(Const.RedisConst.AccessFailed).SetAsync(loginDto.UserName, ++errCount);
                    throw new BizException(L("IncorrectPassword"), errCount > 2 ? ErrorCodeEnum.PwdErrorLimit : (ErrorCodeEnum?)null);
                }
                //正确登录后清掉计数
                await CacheManager.GetCache<string,int>(Const.RedisConst.AccessFailed).RemoveAsync(loginDto.UserName);
                re= ObjectMapper.Map<UserMiniDto>(user);
            }
            return ObjectMapper.Map(staff,re);
        }

        /// <summary>
        /// 设置用户的ImId
        /// </summary>
        /// <param name="input"></param>
        [HttpPut]
        public async Task SetImId([FromQuery]SetImIdInput input)
        {
            await _userRep.GetAll().Where(m=>m.Id==input.UserId).UpdateFromQueryAsync(m=> new UserEntity{ ImId=input.ImId});
        }
    }
}


